package cate.game.role.res.guild.po.treasurehouse;

import cate.common.table.d.GDFunc;
import cate.common.table.d.GDGuild;
import cate.common.table.guild.treasurehouse.GuildTreasureHouseItemRow;
import cate.common.util.GameResult;
import cate.common.util.TimeTool;
import cate.game.chat.ChatContentParam;
import cate.game.notice.NoticeParam;
import cate.game.res.MixRes;
import cate.game.role.res.guild.GuildFuncBase;
import cate.game.role.res.guild.po.GuildPO;
import cate.game.role.res.guild.po.treasurehouse.msg.GuildTreasureItemResp;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Transient;

import java.util.*;

@NoArgsConstructor
@NoteClass("宝库物品")
public class GuildTreasureItem extends GuildFuncBase {
    @Getter
    @NoteField("配置ID")
    public int tid;
    @Getter
    @NoteField("物品列表")
    private List<GuildTreasureTimeItem> timeBasedList;
    @Transient
    @NoteField("下次检测时间")
    private long checkTime;

    public GuildTreasureItem(int tid) {
        this.tid = tid;
        this.timeBasedList = new LinkedList<>();
    }

    @Override
    public int getFuncId() {
        return GDFunc.GuildFunc.TREASURE_HOUSE;
    }

    @Override
    public void initialize(GuildPO parent) {
        super.initialize(parent);
        if (timeBasedList == null) {
            timeBasedList = new LinkedList<>();
        }
        sort();
    }

    /**
     * 获取配置
     */
    private GuildTreasureHouseItemRow onGetRow() {
        return getFuncDependent().guild.game.table.guildTreasureHouse.item.get(tid);
    }

    /**
     * 获取按时间排序的物品列表
     */
    public void sort() {
        synchronized (this) {
            timeBasedList.sort(Comparator.comparingLong(GuildTreasureTimeItem::getExpiredTimeStamp));
            checkTime = timeBasedList.stream().mapToLong(GuildTreasureTimeItem::getExpiredTimeStamp).min().orElse(0L);
        }
    }

    /**
     * 获取物品总数量
     */
    @JsonIgnore
    public int getTotalUnitNum() {
        return timeBasedList.stream().mapToInt(GuildTreasureTimeItem::getUnitNum).sum();
    }

    /**
     * 是否为空
     */
    @JsonIgnore
    public boolean isEmpty() {
        return getTotalUnitNum() == 0;
    }

    /**
     * 添加物品
     *
     * @param num 数量
     * @return 携带增加的实际物品
     */
    public GameResult<MixRes> add(int num, int funcId) {
        synchronized (this) {
            GameResult<MixRes> r = new GameResult<>();
            GuildTreasureHouseItemRow row = onGetRow();
            if (row == null) {
                return r.fail("该物品不能放入宝库");
            }
            if (funcId == GDFunc.NULL && !row.playerCanPut) {
                return r.fail("该物品不能放入宝库");
            }
            if (num > row.saveNumLimit - getTotalUnitNum()) {
                return r.fail("该道具在宝库中已达上限");
            }
            long expiredTime = System.currentTimeMillis() + row.PD * TimeTool.TimeCons.DAY;
            GuildTreasureTimeItem timeItem = new GuildTreasureTimeItem(expiredTime, num);
            timeBasedList.add(timeItem);
            r.data = new MixRes(onGetRow().itemStr).multiply(num);
            sort();
            return r.success();
        }
    }

    /**
     * 扣除物品
     *
     * @param num 数量
     * @return 扣除的实际物品
     */
    public GameResult<MixRes> reduce(int num) {
        synchronized (this) {
            GameResult<MixRes> r = new GameResult<>();
            GuildTreasureHouseItemRow row = onGetRow();
            if (row == null) {
                return r.fail("物品错误");
            }
            if (getTotalUnitNum() < num) {
                return r.fail("已经没有库存");
            }
            int temp = num;
            for (GuildTreasureTimeItem timeItem : timeBasedList) {
                temp = timeItem.reduce(temp);
                if (temp <= 0) {
                    break;
                }
            }
            r.data = new MixRes(row.itemStr).multiply(num);
            timeBasedList.removeIf(GuildTreasureTimeItem::checkNumZero);
            sort();
            return r.success();
        }
    }

    /**
     * 循环
     */
    public boolean tick() {
        long nowTime = System.currentTimeMillis();
        if (checkTime == 0 || nowTime < checkTime) {
            return false;
        }
        synchronized (this) {
            long changeNum = timeBasedList.stream().filter(this::checkExpired).count();
            if (changeNum > 0L) {
                timeBasedList.removeIf(GuildTreasureTimeItem::checkExpired);
                sort();
                noticeOnline();
                return true;
            }
        }
        return false;
    }

    /**
     * 检测物品是否过期
     *
     * @param item 单个限时物品
     */
    private boolean checkExpired(GuildTreasureTimeItem item) {
        if (!item.checkExpired()) {
            return false;
        }
        GuildTreasureHouseItemRow row = onGetRow();
        if (row != null) {
            NoticeParam param = NoticeParam.of(GDGuild.log.TREASURE_EXPIRED,
                    Collections.singletonList(ChatContentParam.c(ChatContentParam.TYPE_MIX_RES, new MixRes(row.itemStr).multiply(item.onGetOriginUnitNum())))
            );
            funcDependent.getGuild().treasureHouse.logPO.addLog(param);
        }
        return true;
    }

    /**
     * 通知在线玩家
     */
    private void noticeOnline() {
        funcDependent.guild.noticeOnline(m -> m.sendNow(new GuildTreasureItemResp(this)));
    }
}
